package com.crazymaker.springcloud.delaydelete;

import cn.hutool.core.thread.NamedThreadFactory;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

public class DelayTrigger<T> {
    private static final int capacity = 10000;
    private static final long DELAY_TIME = 10 * 1000;// 10秒
    private static final AtomicInteger cnt = new AtomicInteger();
    private final DelayQueue<DelayElement<T>> queue = new DelayQueue<DelayElement<T>>();
    private IDelayHandler<T> delayHandler;
    private ExecutorService producer = new ThreadPoolExecutor(1, 2, 1L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(capacity),
            new NamedThreadFactory("DelayTrigger_Producer", false), new ThreadPoolExecutor.DiscardPolicy());
    private ExecutorService consumer = new ThreadPoolExecutor(2, 4, 1L, TimeUnit.SECONDS,
            new ArrayBlockingQueue<Runnable>(capacity),
            new NamedThreadFactory("DelayTrigger_Consumer", false), new ThreadPoolExecutor.DiscardPolicy());
 
    private volatile boolean running = true;
    
    private final Listener listener = new Listener();
 
    
    
    
    private long delayTime = DELAY_TIME;
 
    public DelayTrigger(IDelayHandler<T> delayHandler) {
        this(delayHandler, DELAY_TIME);
    }
 
    public DelayTrigger(IDelayHandler<T> delayHandler, long delayTime) {
        this.delayHandler = delayHandler;
        this.delayTime = delayTime;
        this.listener.setName("DelayTrigger-" + cnt.incrementAndGet());
        this.listener.setDaemon(true);
        this.listener.start();
    }
 
    private class Listener extends Thread {
 
        @Override
        public void run() {
            while (running && !isInterrupted()) {
                try {
                    final DelayElement<T> t = queue.poll(5, TimeUnit.SECONDS);
                    if (t != null) {
                        consumer.execute(new Runnable() {
 
                            @Override
                            public void run() {
                                delayHandler.handle(t.getT());
                            }
 
                        });
                    }
                } catch (InterruptedException e) {
                    // ignore interrupt
                }
            }
        }
    }
 
    public void put(final T t) {
        producer.execute(new Runnable() {
 
            @Override
            public void run() {
                queue.add(new DelayElement<T>(t, delayTime));
            }
 
        });
    }
 
    /**
     * 关闭资源
     */
    public void destroy() {
        this.producer.shutdownNow();
        this.running = false;
        this.consumer.shutdownNow();
        this.queue.clear();
    }
 
    /**
     * 最大可能释放资源
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        destroy();
    }
 
}